package msgs

import (
	"encoding/binary"
	"fmt"
	"ospf/common"
)

type Header struct {
	Version      uint8
	MessageType  packetType
	PacketLength uint16
	// 这个包是从哪个路由器发过来的，记录了路由器的id
	SourceRouter common.ID
	Area         common.ID
	CheckSum     uint16
	AuthType     uint16
	AuthData     uint64
}

// Serialize map Header struct to []byte stream.
func (h *Header) Serialize(data []byte) (err error) {
	data[0] = h.Version
	data[1] = uint8(h.MessageType)
	binary.BigEndian.PutUint16(data[2:4], h.PacketLength)
	copy(data[4:8], h.SourceRouter[:])
	copy(data[8:12], h.Area[:])
	binary.BigEndian.PutUint16(data[12:14], h.CheckSum)
	binary.BigEndian.PutUint16(data[14:16], h.AuthType)
	binary.BigEndian.PutUint64(data[16:24], h.AuthData)
	return nil
}

// Deserialize map []byte to Header
func (h *Header) Deserialize(data []byte) (err error) {
	// prejudge length
	if l := len(data); l < headerLen {
		return common.ErrDeserialize(fmt.Sprintf("not enough bytes for header: %d, at least: %d",
			l, headerLen))
	}

	// start mapping
	h.Version = data[0]
	h.MessageType = packetType(data[1])
	h.PacketLength = binary.BigEndian.Uint16(data[2:4])
	h.SourceRouter = common.ID(data[4:8])
	h.Area = common.ID(data[8:12])
	h.CheckSum = binary.BigEndian.Uint16(data[12:14])
	h.AuthType = binary.BigEndian.Uint16(data[14:16])
	h.AuthData = binary.BigEndian.Uint64(data[16:24])
	return nil
}

func GenHeader(msgType packetType, ip common.ID) *Header {
	return &Header{
		Version:      2,
		MessageType:  msgType,
		PacketLength: 0,
		SourceRouter: ip,
		Area:         common.ID{1, 2, 3, 4},
		CheckSum:     0,
		AuthType:     0,
		AuthData:     0,
	}
}

type LSAHeader struct {
	// lsa包header部分
	// lsa 老化时间
	LSAge   uint16
	Options Options
	// 规定了当前LSA的种类
	LSType LSType
	// 本路由器对应网卡IP
	LinkStateID common.ID
	// 本路由器Router ID
	AdvertisingRouter common.ID
	SequenceNumber    uint32
	Checksum          uint16
	Length            uint16
}

func GenLSAHeader(lsType LSType, ip common.ID, id common.ID) *LSAHeader {
	return &LSAHeader{
		LSAge:             uint16(1 << 15),
		Options:           ExternalRouting,
		LSType:            lsType,
		LinkStateID:       common.CIDR(ip),
		AdvertisingRouter: id,
		SequenceNumber:    0,
		Checksum:          0,
		Length:            0,
	}
}

// Serialize 将 LSAHeader 转为比特流存入data数组中
func (h *LSAHeader) Serialize(data []byte) (err error) {
	binary.BigEndian.PutUint16(data[0:2], h.LSAge)
	data[2] = byte(h.Options)
	data[3] = byte(h.LSType)
	copy(data[4:8], h.LinkStateID[:])
	copy(data[8:12], h.AdvertisingRouter[:])
	binary.BigEndian.PutUint32(data[12:16], h.SequenceNumber)
	binary.BigEndian.PutUint16(data[16:18], h.Length)
	binary.BigEndian.PutUint16(data[18:20], h.Checksum)
	return nil
}

// Deserialize 从data中读取信息并存入 LSAHeader 中
func (h *LSAHeader) Deserialize(data []byte) (err error) {
	h.LSAge = binary.BigEndian.Uint16(data[0:2])
	h.Options = Options(data[2])
	h.LSType = LSType(data[3])
	h.LinkStateID = common.ID(data[4:8])
	h.AdvertisingRouter = common.ID(data[8:12])
	h.SequenceNumber = binary.BigEndian.Uint32(data[12:16])
	h.Checksum = binary.BigEndian.Uint16(data[16:18])
	h.Length = binary.BigEndian.Uint16(data[18:20])
	return nil
}
